#ifndef BLOCKQUEUE_H
#define BLOCKQUEUE_H

#include <mutex>
#include <deque>
#include <condition_variable>
#include <sys/time.h>
#include <assert.h>
template<class T>
//定义阻塞队列的类BlockDeque，用于线程间通信
class BlockDeque
{
public:
    //阻塞队列的构造函数，用于初始化阻塞队列的最大容量
    explicit BlockDeque(size_t MaxCapacity = 1000);
    //阻塞队列的析构函数
    ~BlockDeque();
    //用于清空阻塞队列的函数
    void Clear();
    //判定阻塞队列是否为空
    bool Empty();
    //判定阻塞队列是否为满
    bool Full();
    //关闭阻塞队列，用于通知所有等待的线程
    void Close();
    //返回队列大小的函数
    size_t Size();
    //返回队列的最大容量
    size_t Capacity();
    //返回队列的头部元素
    T Front();
    //返回队列尾部的元素
    T Back();
    //队列尾插的函数
    void Push_back(const T& item);
    //队列头插的函数
    void Push_front(const T& item);
    //队列弹出的函数，用于从队列中弹出元素
    bool Pop(T& item);
    //超时等待弹出队列的函数，用于在指定时间内等待队列有元素弹出
    bool Pop(T& item,int timeout);
    //通知队列有元素的函数，用于通知消费者线程去消费
    void Flush();
private: 
    //阻塞对列的容器
    std::deque<T> deq_;   
    //阻塞队列的最大容量
    size_t capacity_;
    //阻塞队列的互斥锁
    std::mutex mtx_;
    //阻塞队列是否关闭的标志位
    bool isClose_;
    //阻塞队列的消费者条件变量
    std::condition_variable condConsumer_;
    //阻塞队列的生产者条件变量
    std::condition_variable condProducer_;
};
//阻塞队列的构造函数，用于初始化阻塞队列的最大容量
template<class T>
BlockDeque<T>::BlockDeque(size_t MaxCapacity):capacity_(MaxCapacity)   //用参数MaxCapacity初始化阻塞队列的最大容量
{
    //判断最大容量是否大于零
    assert(MaxCapacity > 0);
    //初始化阻塞队列是否关闭的标志位为false
    isClose_ = false;
}
//阻塞队列的析构函数，用于关闭阻塞队列
template<class T>
BlockDeque<T>::~BlockDeque()
{
    //关闭阻塞队列
    Close();
}
//阻塞队列的关闭函数，用于关闭阻塞队列
template<class T>
void BlockDeque<T>::Close()
{
    //判断阻塞队列是否关闭，如果isClose_为false，也就是没有关闭，则if为True
    if(!isClose_)
    {
        //加锁，确保在阻塞队列关闭时，没有其他线程在操作阻塞队列
        std::lock_guard<std::mutex> locker(mtx_);
        //将阻塞队列的队列容器清空
        deq_.clear();
        //将阻塞队列是否关闭的标志位设置为True
        isClose_ = true;
    }
    //阻塞队列已经关闭，通知所有的生产者线程
    condProducer_.notify_all();
    //阻塞队列已经关闭，通知所有的消费者线程
    condConsumer_.notify_all();
}
//阻塞队列的刷新函数，用于通知一个消费者线程去消费
template<class T>
void BlockDeque<T>::Flush()
{
    //通知一个消费者线程去消费
    condConsumer_.notify_one();
}
//阻塞队列的清空函数，用于清空阻塞队列
template<class T>
void BlockDeque<T>::Clear()
{
    //将阻塞队列上锁，确保在清空阻塞队列时，没有其他线程在操作阻塞队列
    std::lock_guard<std::mutex> locker(mtx_);
    //将阻塞队列的队列容器清空
    deq_.clear();
}
//获取阻塞队列的头部元素的函数
template<class T>
T BlockDeque<T>::Front()
{
    std::lock_guard<std::mutex> locker(mtx_);
    return deq_.front();
}
//获取阻塞队列的尾部元素的函数
template<class T>
T BlockDeque<T>::Back()
{
    std::lock_guard<std::mutex> locker(mtx_);
    return deq_.back();
}
//获取阻塞队列当前有多少个元素的函数
template<class T>
size_t BlockDeque<T>::Size()
{
    std::lock_guard<std::mutex> locker(mtx_);
    return deq_.size();
}
//获取阻塞队列的最大容量的函数
template<class T>
size_t BlockDeque<T>::Capacity()
{
    std::lock_guard<std::mutex> locker(mtx_);
    return capacity_;
}
//将元素插入到阻塞队列的尾部的函数
template<class T>
void BlockDeque<T>::Push_back(const T& item)
{
    //在尾插的时候，先将阻塞队列上锁，确保在尾插时，没有其他线程在操作阻塞队列
    std::unique_lock<std::mutex> locker(mtx_);
    //如果当前阻塞队列已满，等待消费者线程消费
    while(deq_.size() >= capacity_)
    {
        //因为队列已满，所以生产者线程需要等待
        condProducer_.wait(locker);
    }
    //当前队列不满，所以可以尾插，尾插一个元素
    deq_.push_back(item);
    //通知消费者线程去消费
    condConsumer_.notify_one();
}
//将元素插入到阻塞队列的头部的函数
template<class T>
void BlockDeque<T>::Push_front(const T& item)
{
    //在头插的时候，先将阻塞队列上锁，确保在头插时，没有其他线程在操作阻塞队列
    std::unique_lock <std::mutex> locker(mtx_);
    //如果当前阻塞队列已满，等待消费者线程消费
    while(deq_.size() >= capacity_)
    {
        //因为队列已满，所以生产者线程需要等待
        condProducer_.wait(locker);
    }
    //跳出了循环，说明队列不满，所以可以头插，头插一个元素
    deq_.push_back(item);
    //通知消费者线程去消费
    condConsumer_.notify_one();
}
//判断阻塞队列是否为空的函数
template<class T>
bool BlockDeque<T>::Empty()
{
    //在判断阻塞队列是否为空的时候，先将阻塞队列上锁，确保在判断时，没有其他线程在操作阻塞队列
    std::lock_guard<std::mutex> locker(mtx_);
    //返回队列是否为空
    return deq_.empty();
}
//判断队列是否为满的函数
template<class T>
bool BlockDeque<T>::Full()
{
    //在判断阻塞队列是否已满的时候，先将阻塞队列上锁，确保在判断时，没有其他线程在操作阻塞队列
    std::lock_guard<std::mutex> locker(mtx_);
    //返回队列是否已经到了最大容量
    return deq_.size() >= capacity_;
}
//从阻塞队列中弹出一个元素的函数
template<class T>
bool BlockDeque<T>::Pop(T& item)
{
    //在弹出元素的时候，先将阻塞队列上锁，确保在弹出元素时，没有其他线程在操作阻塞队列
    std::unique_lock<std::mutex> locker(mtx_);
    //循环判断当前队列是否为空
    while(deq_.empty())
    {
        ////如果当前队列为空，则消费者线程需要等待
        condConsumer_.wait(locker);
        //如果队列已经关闭了
        if(isClose_)
        {
            //队列已经关闭了，所以返回false
            return false;
        }
    }
    //跳出了循环，说明队列不为空，所以可以弹出一个元素，将item赋值为队列的头部元素
    item = deq_.front();
    //弹出队列的头部元素
    deq_.pop_front();
    //因为弹出了一个元素，所以需要通知生产者线程去生产
    condProducer_.notify_one();
    //返回true
    return true;
}
//在等待时间内，从阻塞队列中弹出一个元素的函数
template<class T>
bool BlockDeque<T>::Pop(T& item,int timeout)
{
    //将阻塞队列上锁，防止在弹出操作时，其他线程在操作阻塞队列
    std::unique_lock<std::mutex> locker(mtx_);
    //循环判断队列是否为空，空，则进入循环
    while(deq_.empty())
    {
        //如果在等待时间内，队列还是空，则返回false
        if(condConsumer_.wait_for(locker,std::chrono::seconds(timeout)) == std::cv_status::timeout)
        {
            return false;
        }
        //如果队列已经关闭了，也返回false
        if(isClose_)
        {
            return false;
        }
    }
    //跳出了循环，说明队列不为空，所以可以弹出一个元素，将item赋值为队列的头部元素
    item = deq_.front();
    //弹出队列的头部元素
    deq_.pop_front();
    //因为弹出了一个元素，所以需要通知生产者线程去生产
    condProducer_.notify_one();
    //返回true
    return true;
}
#endif